﻿using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using PetaPoco;
using PmSoft;
using PmSoft.ApplicationContext;
using PmSoft.Caching;
using PmSoft.DBContext;

namespace Modules.System.Settings
{
    /// <summary>
    /// 设置Repository
    /// </summary>
    /// <typeparam name="TSettingsEntity">设置的实体类</typeparam>
    public class SettingRepository<TSettingsEntity> where TSettingsEntity : class, IEntity, new()
    {
        private readonly IApplicationContext applicationContext;
        private readonly IConfiguration configuration;
        private readonly DefaultDbContext dbContext;

        public SettingRepository(IApplicationContext applicationContext,
            IConfiguration configuration,
            DefaultDbContext dbContext)
        {
            this.applicationContext = applicationContext;
            this.configuration = configuration;
            this.dbContext = dbContext;
        }

        private static ReaderWriterLockSlim RWLock = new ReaderWriterLockSlim();

        // 缓存服务
        protected ICacheService CacheService
        { get { return applicationContext.GetService<ICacheService>(); } }

        /// <summary>
        /// 缓存设置
        /// </summary>
       	protected EntityCacheService<TSettingsEntity> EntityCacheService { get => applicationContext.GetService<EntityCacheService<TSettingsEntity>>(); }

        /// <summary>
        /// 获取设置
        /// </summary>
        /// <returns>tb_Settings</returns>
        public TSettingsEntity Get()
        {
            string classType = GetClassType();

            TSettingsEntity? result = CacheService.Get<TSettingsEntity>(EntityCacheService.GetCacheKeyOfEntity(classType));

            if (result == null)
            {
                var sql = Sql.Builder;
                sql.Select("settings").From("sys_setting").Where("class_type=@0", classType);

                string settingsJson = dbContext.FirstOrDefault<string>(sql);

                if (settingsJson == null)
                {
                    result = new TSettingsEntity();
                    Save(result);
                }
                else
                {
                    result = Deserialize(settingsJson);
                }
                CacheService.Add(EntityCacheService.GetCacheKeyOfEntity(classType), result, CachingExpirationType.RelativelyStable);
            }
            if (result == null)
                throw new ArgumentNullException(nameof(result));
            return result;
        }

        /// <summary>
        /// 保存设置
        /// </summary>
        /// <param name="settings">settings</param>
        public void Save(TSettingsEntity settings)
        {
            string classType = GetClassType();
            string? settingsJson = Serialize(settings);

            var sql = Sql.Builder;
            sql.Select("count(class_type)").From("sys_setting").Where("class_type=@0", classType);

            RWLock.EnterWriteLock();

            try
            {
                dbContext.OpenSharedConnection();

                int count = dbContext.ExecuteScalar<int>(sql);
                sql = Sql.Builder;
                if (count > 0)
                    sql.Append("update sys_setting set settings=@0 where class_type=@1", settingsJson, classType);
                else
                    sql.Append("insert into sys_setting (class_type,settings) values (@0,@1)", classType, settingsJson);

                dbContext.Execute(sql);
            }
            finally
            {
                dbContext.CloseSharedConnection();
                RWLock.ExitWriteLock();
            }
            CacheService.Set(EntityCacheService.GetCacheKeyOfEntity(classType), settings, CachingExpirationType.RelativelyStable);
            //EntityCacheService.IncreaseEntityCacheVersion(classType);
        }

        /// <summary>
        /// 获取ClassType
        /// </summary>
        /// <returns></returns>
        private string GetClassType()
        {
            return typeof(TSettingsEntity).Name;
            //string? assemblyQualifiedName = typeof(TSettingsEntity).AssemblyQualifiedName;
            //if (string.IsNullOrEmpty(assemblyQualifiedName))
            //    throw new ArgumentNullException(nameof(assemblyQualifiedName));
            //string[] parts = assemblyQualifiedName.Split(',');
            //return parts[0] + "," + parts[1];
        }

        /// <summary>
        /// 把TSettingsEntity对象转换成xml
        /// </summary>
        /// <param name="settingsEntity">被转换的对象</param>
        /// <returns>序列化后的xml字符串</returns>
        private string Serialize(TSettingsEntity settingsEntity)
        {
            string json = string.Empty;

            if (settingsEntity != null)
            {
                json = JsonConvert.SerializeObject(settingsEntity);
            }
            return json;
        }

        /// <summary>
        /// 把json的字符串反序列化成SettingsEntity对象
        /// </summary>
        /// <param name="json">被反序列化的xml字符串</param>
        /// <returns>反序列化后的SettingsEntity</returns>
        private TSettingsEntity? Deserialize(string json)
        {
            if (!string.IsNullOrEmpty(json))
            {
                return JsonConvert.DeserializeObject<TSettingsEntity>(json);
            }
            return null;
        }
    }
}